package fr.lip6.meta.ple.generation.fh.java;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import org.eclipse.emf.common.util.EList;
import org.eclipse.gmt.modisco.java.AbstractTypeDeclaration;
import org.eclipse.gmt.modisco.java.BodyDeclaration;
import org.eclipse.gmt.modisco.java.ClassDeclaration;
import org.eclipse.gmt.modisco.java.ConstructorDeclaration;
import org.eclipse.gmt.modisco.java.MethodDeclaration;
import org.eclipse.gmt.modisco.java.SingleVariableDeclaration;
import org.eclipse.gmt.modisco.java.emf.impl.ClassDeclarationImpl;
import org.eclipse.gmt.modisco.java.emf.impl.ConstructorDeclarationImpl;
import org.eclipse.gmt.modisco.java.emf.impl.FieldDeclarationImpl;
import org.eclipse.gmt.modisco.java.emf.impl.InterfaceDeclarationImpl;
import org.eclipse.gmt.modisco.java.emf.impl.MethodDeclarationImpl;
import org.eclipse.gmt.modisco.java.emf.impl.PackageImpl;

//import org.eclipse.uml2.uml.UMLPackage;



//import Jakarta.symtab.CompilationUnit;
import artefact.umlClassDiagram.CreateAttribute;
import artefact.umlClassDiagram.CreateClass;
import artefact.umlClassDiagram.CreateOperation;
import artefact.umlClassDiagram.CreateOperationRefinement;
import fr.lip6.meta.ple.featureIdentification.Feature;
import fr.lip6.meta.ple.generation.strategy.GenerateFromXmiStrategy;
import fr.lip6.meta.tools.*;

public class GenerateFromXmiFHJava extends GenerateFromXmiStrategy {
	public static ClassDeclarationImpl getClassDeclaration(String path, String packagename, String classname) {
		ClassDeclarationImpl c = null;
		PackageImpl p = readpackage(path, packagename);
		Iterator<AbstractTypeDeclaration> typeDecls = p.getOwnedElements().iterator();

		while (typeDecls.hasNext()) {
			AbstractTypeDeclaration ab = typeDecls.next();

			if (ab instanceof ClassDeclaration) {
				ClassDeclarationImpl d = (ClassDeclarationImpl) ab;

				if(d.getName().equals(classname)) {
					c=d;
					break;
				}
			}
		}

		return c;
	}

	public static InterfaceDeclarationImpl getInterfaceDeclaration(String path, String packagename, String classname) {
		InterfaceDeclarationImpl c = null;
		PackageImpl p = readpackage(path, packagename);
		Iterator<AbstractTypeDeclaration> classs = p.getOwnedElements().iterator();

		while (classs.hasNext()) {
			AbstractTypeDeclaration ab = classs.next();

			if(ab instanceof InterfaceDeclarationImpl) {
				InterfaceDeclarationImpl d = (InterfaceDeclarationImpl) ab;

				if(d.getName().equals(classname)) {
					c=d;
					break;
				}
			}
		}

		return c;
	}

	public static FieldDeclarationImpl getFieldDeclaration(String pathe,String packagename,String classname,String fieldname)
	{
		FieldDeclarationImpl fd=null;
		ClassDeclarationImpl d= getClassDeclaration(pathe, packagename, classname);
		if(d!=null)
		{
			EList<BodyDeclaration> bodys=d.getBodyDeclarations();
			//read body declaration 
			for(BodyDeclaration bo:bodys)
			{

				if(bo instanceof FieldDeclarationImpl)
				{FieldDeclarationImpl fd1=(FieldDeclarationImpl) bo;

				if(fd1.getFragments().get(0).getName().equals(fieldname))
				{
					fd=fd1;
					break;
				}
				}
			}
		}

		return fd;

	}

	public static MethodDeclarationImpl getInterFaceMethoddeclaration(String pathe,String packagename,String classname,String methodname)
	{
		MethodDeclarationImpl m=null;

		InterfaceDeclarationImpl d= getInterfaceDeclaration(pathe, packagename, classname);
		if(d!=null)
		{
			EList<BodyDeclaration> bodys=d.getBodyDeclarations();
			//read body declaration 
			for(BodyDeclaration bo:bodys)
			{

				if (bo instanceof MethodDeclaration)
				{
					MethodDeclarationImpl m1= (MethodDeclarationImpl) bo;
					if(m1.getName().equals(methodname))
					{
						m=m1;break;
					}

				}
			}
		}

		return m;
	}

	public static List<MethodDeclaration> getInterFaceoperations(Feature f, String packagename, String classname) {
		ArrayList<MethodDeclaration> list=new ArrayList<MethodDeclaration>();

		for(Trigger t : f) {
			StatementPrimitive st = (StatementPrimitive)t;

			if (st.getPrimitive() instanceof CreateOperation) {
				CreateOperation c=(CreateOperation) st.getPrimitive();
				String [] lien=c.getLien().split("::");

				if(c.getOwener().equals(classname) && packagename.equals(lien[1])) {
					if(!(c.getOwener().equals(c.getName()))) {
						System.out.println("inter face is maissssssss");
						MethodDeclaration fd = getInterFaceMethoddeclaration(lien[0], packagename, classname, c.getName());

						list.add(fd);
					}



				}

			}
		}
		return list;

	}

	public static MethodDeclarationImpl getMethodDeclaration(	String path,
																String packagename,
																String classname,
																String methodname,
																String[] parameters	) {
		ClassDeclarationImpl classDecl = getClassDeclaration(path, packagename, classname);
		int paramsLength = parameters.length;

		if(classDecl != null) {
			EList<BodyDeclaration> bodyDecls = classDecl.getBodyDeclarations();

			//read body declarations
			for(BodyDeclaration bodyDecl : bodyDecls) {
				if (bodyDecl instanceof MethodDeclaration) {
					MethodDeclarationImpl methodDecl = (MethodDeclarationImpl) bodyDecl;

					if(methodDecl.getName().equals(methodname)) {
						EList<SingleVariableDeclaration> svdList = methodDecl.getParameters();

						if (svdList.size() == paramsLength) {
							int i = 0;
							for(SingleVariableDeclaration param : svdList) {
								if (param.getType().getType().getName().equals(parameters[i]))
									i++;
								else
									break;
							}
							if (i == paramsLength)
								return methodDecl;
						}
					}
				}
			}
		}

		return null;
	}

	public static List<MethodDeclaration> getAllOperations(Feature f, String packagename, String classname) {
		ArrayList<MethodDeclaration> list = new ArrayList<MethodDeclaration>();

		for(Trigger t : f) {
			StatementPrimitive st = (StatementPrimitive) t;

			if (st.getPrimitive() instanceof CreateOperation) {
				CreateOperation crOp = (CreateOperation) st.getPrimitive();
				String [] lien = crOp.getLien().split("::");
				String params = lien.length > 2 ? lien[2] : null;
				String[] paramsArray = params == null ? new String[0] : params.substring(1, params.length()-1).split(",");
				
				if (paramsArray.length == 1 && paramsArray[0].equals("")) paramsArray = new String[0];

				if (crOp.getOwener().equals(classname) && packagename.equals(lien[1])) {
					if (!(crOp.getOwener().equals(crOp.getName()))) {
						MethodDeclaration fd = getMethodDeclaration(lien[0], packagename, classname, crOp.getName(), paramsArray);

						list.add(fd);
					}
				}
			}
		}

		return list;
	}

	public static List<MethodDeclaration> getRefinementOperations(Feature f, String packagename, String classname) {
		ArrayList<MethodDeclaration> list=new ArrayList<MethodDeclaration>();

		for(Trigger t : f) {
			StatementPrimitive st = (StatementPrimitive) t;

			if (st.getPrimitive() instanceof CreateOperationRefinement) {
				CreateOperationRefinement c = (CreateOperationRefinement) st.getPrimitive();
				String [] lien = c.getLien().split("::");
				String params = lien.length > 2 ? lien[2] : null;
				String[] paramsArray = params == null ? new String[0] : params.substring(1, params.length()-1).split(",");
				if (paramsArray.length == 1 && paramsArray[0].equals("")) paramsArray = new String[0];

				if(c.getOwner().equals(classname) && packagename.equals(lien[1])) {
					if(!(c.getOwner().equals(c.getName()))) {
						MethodDeclaration fd = getMethodDeclaration(lien[0], packagename, classname, c.getName(), paramsArray);

						list.add(fd);
					}
				}
			}
		}

		return list;
	}

	public static ConstructorDeclarationImpl getConstructorDeclaration(	String path,
			String packagename,
			String classname,
			String methodname,
			String[] parameters	) {
		ClassDeclarationImpl classDecl = getClassDeclaration(path, packagename, classname);
		EList<BodyDeclaration> bodyDecls = classDecl.getBodyDeclarations();
		int paramsLength = parameters.length;

		//read body declarations
		for(BodyDeclaration bodyDecl : bodyDecls) {
			if (bodyDecl instanceof ConstructorDeclaration) {
				ConstructorDeclarationImpl consDecl = (ConstructorDeclarationImpl) bodyDecl;

				if(consDecl.getName().equals(methodname)) {
					EList<SingleVariableDeclaration> svdList = consDecl.getParameters();

					if (svdList.size() == paramsLength) {
						int i = 0;
						for(SingleVariableDeclaration param : svdList) {
							if (param.getType().getType().getName().equals(parameters[i]))
								i++;
							else
								break;
						}
						if (i == paramsLength)
							return consDecl;
					}
				}
			}
		}

		return null;
	}

	public static ArrayList<ConstructorDeclarationImpl> getConstructorsDeclaration(Feature feat, String packagename, String classname) {
		ArrayList<ConstructorDeclarationImpl> list = new ArrayList<ConstructorDeclarationImpl>();

		for(Trigger tr : feat) {
			StatementPrimitive st = (StatementPrimitive) tr;

			if (st.getPrimitive() instanceof CreateOperation) {
				CreateOperation crOp = (CreateOperation) st.getPrimitive();
				String [] lien = crOp.getLien().split("::");
				String xmi_file = lien[0];
				String pckg = lien[1];
				String params = lien.length > 2 ? lien[2] : null;
				String[] paramsArray = params == null ? new String[0] : params.substring(1, params.length()-1).split(",");
				if (paramsArray.length == 1 && paramsArray[0].equals("")) paramsArray = new String[0];

				if (crOp.getOwener().equals(classname) && packagename.equals(pckg)) {
					if ((crOp.getOwener().equals(crOp.getName()))) {
						ConstructorDeclarationImpl consDecl = getConstructorDeclaration(xmi_file, packagename, classname, crOp.getName(), paramsArray);

						list.add(consDecl);
					}
				}
			}
		}

		return list;
	}

	public static List<FieldDeclarationImpl> getFieldsDeclaration(Feature f, String packagename, String classname) {
		ArrayList<FieldDeclarationImpl> list = new ArrayList<FieldDeclarationImpl>();

		for(Trigger t : f)
		{
			StatementPrimitive st = (StatementPrimitive)t;
			if (st.getPrimitive() instanceof CreateAttribute){
				CreateAttribute c=(CreateAttribute) st.getPrimitive();
				String [] lien=c.getLien().split("::");
				if(c.getOwner().equals(classname) && packagename.equals(lien[1]))
				{



					FieldDeclarationImpl fd	=getFieldDeclaration(lien[0], packagename, classname, c.getName());

					list.add(fd);



				}

			}
		}
		
		return list;
	}

	public static List<ClassDeclaration> getClassesDeclaration(Feature f, String packagename) {
		ArrayList<ClassDeclaration> list = new ArrayList<ClassDeclaration>();

		for(Trigger t : f) {
			StatementPrimitive st = (StatementPrimitive) t;

			if (st.getPrimitive() instanceof CreateClass) {
				CreateClass c = (CreateClass) st.getPrimitive();

				if(c.getOwener().equals(packagename)) {
					ClassDeclarationImpl cd = getClassDeclaration(c.getLien(), packagename, c.getName());
					Iterator<BodyDeclaration> listatt=cd.getBodyDeclarations().iterator();

					while(listatt.hasNext()) {
						cd.getBodyDeclarations().remove(0);
					}

					Iterator<FieldDeclarationImpl> fds= getFieldsDeclaration(f, packagename, c.getName()).iterator();

					while(fds.hasNext()) {
						FieldDeclarationImpl fd=fds.next();

						cd.getBodyDeclarations().add(fd);
					}

					Iterator<ConstructorDeclarationImpl> consDecls = getConstructorsDeclaration(f, packagename, c.getName()).iterator();

					while(consDecls.hasNext()) {
						ConstructorDeclarationImpl consDecl = (ConstructorDeclarationImpl) consDecls.next();

						cd.getBodyDeclarations().add(consDecl);
					}

					Iterator<MethodDeclaration> ops= getAllOperations(f, packagename, c.getName()).iterator();

					while(ops.hasNext()) {
						MethodDeclarationImpl fd1=(MethodDeclarationImpl) ops.next();

						cd.getBodyDeclarations().add(fd1);
					}
					Iterator<MethodDeclaration> refops= getRefinementOperations(f, packagename, c.getName()).iterator();

					while(refops.hasNext()) {
						MethodDeclarationImpl fd1=(MethodDeclarationImpl) refops.next();

						cd.getBodyDeclarations().add(fd1);
					}

					list.add(cd);
					System.out.println("class name "+cd.getName());
				}
			}
		}

		return list;
	}
}
